package utils

import (
	"net"
	"net/http"
	"strings"
)

const (
	unknownValue = "unknown"
	localhostV4  = "127.0.0.1"
	localhostV6  = "::1"
	defaultIP    = "0.0.0.0"
)

// ExtractClientIp 从HTTP请求中提取客户端真实IP，对应Java的extractClientIp方法
func ExtractClientIp(r *http.Request) string {
	// 定义需要检查的IP头字段，按优先级排序
	ipHeaders := []string{
		"X-Forwarded-For",
		"X-Real-IP",
		"Proxy-Client-IP",
		"WL-Proxy-Client-IP",
		"HTTP_CLIENT_IP",
		"HTTP_X_FORWARDED_FOR",
	}

	var clientIp string
	// 依次检查各IP头字段
	for _, header := range ipHeaders {
		clientIp = r.Header.Get(header)
		if !isUnknown(clientIp) {
			break
		}
	}

	// 如果所有头字段都无法获取，则使用远程地址
	if isUnknown(clientIp) {
		clientIp, _, _ = net.SplitHostPort(r.RemoteAddr)
		if clientIp == "" {
			clientIp = r.RemoteAddr
		}
	}

	// 处理本地IP情况
	if isLocalhost(clientIp) {
		localIP, err := getLocalHostIP()
		if err == nil {
			clientIp = localIP
		} else {
			clientIp = defaultIP
		}
	}

	// 处理多IP情况（如X-Forwarded-For可能包含多个IP）
	if strings.Contains(clientIp, ",") {
		clientIp = strings.TrimSpace(strings.Split(clientIp, ",")[0])
	}

	return clientIp
}

// isUnknown 判断IP是否为未知状态
func isUnknown(ip string) bool {
	return ip == "" || strings.EqualFold(ip, unknownValue)
}

// isLocalhost 判断是否为本地回环地址
func isLocalhost(ip string) bool {
	return ip == localhostV4 || ip == localhostV6
}

// getLocalHostIP 获取本机实际IP地址
func getLocalHostIP() (string, error) {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return "", err
	}

	for _, addr := range addrs {
		// 检查是否为IP地址且不是回环地址
		if ipNet, ok := addr.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
			// 检查是否为IPv4地址
			if ipNet.IP.To4() != nil {
				return ipNet.IP.String(), nil
			}
		}
	}

	return localhostV4, nil
}
